﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using ControleRepresentante.Logic.Models;
using ControleRepresentante.Logic.Repositories;
using ControleRepresentante.Logic.Statistics;
using WebSite.Controllers.ControllerExtensions;

namespace WebSite.Controllers
{
    [HandleError(ExceptionType = typeof(RestrictedAreaException), Controller = "RestrictedArea", Action = "Index")]
    public abstract class ControllerBase<TRepository> : Controller
        where TRepository : class, IRepository
    {
        private readonly IControllerExtensionProvider m_ControllerExtensionProvider;

        #region Constructors

        protected ControllerBase(IRepositoryProvider repositoryProvider, IControllerExtensionProvider controllerExtensionProvider, params object[] repositoryParams)
        {
            m_ControllerExtensionProvider = controllerExtensionProvider;
            RepositoryProvider = repositoryProvider;
            Repository = RepositoryProvider.GetRepository<TRepository>(repositoryParams);
        }

        #endregion

        #region Protected Methods

        protected IControllerExtension[] GetControllerExtensions()
        {
            return Area.HasValue
                       ? m_ControllerExtensionProvider.GetExtensions(Area.Value, Repository.GetRepresentante())
                       : new IControllerExtension[0];
        }

        protected Dictionary<Guid, string> ParseIds<TParseRepository, TParseModel, TInnerStatistics>(string ids, Func<TParseModel, string> getName)
            where TParseRepository : IRepository<TParseModel, TInnerStatistics>
            where TParseModel : ModelBase
            where TInnerStatistics : IStatistics
        {
            if (String.IsNullOrEmpty(ids))
            {
                return new Dictionary<Guid, string>();
            }

            IEnumerable<Guid> guidIds = ids
                .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
                .Select(Guid.Parse);
            TParseRepository repository = RepositoryProvider.GetRepository<TParseRepository>();
            IEnumerable<TParseModel> models = repository.GetModelsByIds(guidIds);
            return models.ToDictionary(x => x.Id, getName);
        }

        #endregion

        #region Protected Properties

        protected IRepositoryProvider RepositoryProvider { get; private set; }
        protected TRepository Repository { get; private set; }
        protected virtual Area? Area { get { return null; } }

        #endregion

        #region Permission

        protected void EnsureHasPermission(Operacao operacao)
        {
            if (!HasPermission(operacao))
            {
                throw new RestrictedAreaException();
            }
        }

        protected bool HasPermission(Operacao operacao)
        {
            return !Area.HasValue || HasPermission(Area.Value, operacao);
        }

        protected bool HasPermission(Area area, Operacao operacao)
        {
            return ControllerBase.HasPermission(Repository.User, area, operacao);
        }

        #endregion
    }

    public static class ControllerBase
    {
        internal static bool HasPermission(User user, Area area, Operacao operacao)
        {
            return user != null && user.HasPermission(area, operacao);
        }
    }
}